<script setup lang="ts">
import { onBeforeUnmount, computed, PropType, unref, nextTick, ref, watch, shallowRef } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { IDomEditor, IEditorConfig, i18nChangeLanguage } from '@wangeditor/editor'
import { propTypes } from '@/utils/propTypes'
import { isNumber } from '@/utils/is'
import { useUserStore } from '@/store/modules/user'
import { ElMessage } from 'element-plus'
import { useLocaleStore } from '@/store/modules/locale'

const userStore = useUserStore()
const token = userStore.getToken
const Authorization = `Bearer ${token}`

const localeStore = useLocaleStore()
const headers = ref({ Authorization: Authorization })
const currentLocale = computed(() => localeStore.getCurrentLocale)

i18nChangeLanguage(unref(currentLocale).lang)

const props = defineProps({
  editorId: propTypes.string.def('wangeEditor-1'),
  height: propTypes.oneOfType([Number, String]).def('500px'),
  editorConfig: {
    type: Object as PropType<IEditorConfig>,
    default: () => undefined
  },
  modelValue: propTypes.string.def('')
})

const emit = defineEmits(['change', 'update:modelValue'])

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef<IDomEditor>()

const valueHtml = ref('')

watch(
  () => props.modelValue,
  (val: string) => {
    if (val === unref(valueHtml)) return
    valueHtml.value = val
  },
  {
    immediate: true
  }
)

// 监听
watch(
  () => valueHtml.value,
  (val: string) => {
    emit('update:modelValue', val)
  }
)

const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor
}

// 编辑器配置
const editorConfig = computed((): IEditorConfig => {
  return Object.assign(
    {
      readOnly: false,
      customAlert: (s: string, t: string) => {
        switch (t) {
          case 'success':
            ElMessage.success(s)
            break
          case 'info':
            ElMessage.info(s)
            break
          case 'warning':
            ElMessage.warning(s)
            break
          case 'error':
            ElMessage.error(s)
            break
          default:
            ElMessage.info(s)
            break
        }
      },
      autoFocus: false,
      scroll: true,
      uploadImgShowBase64: true,
      MENU_CONF: {
        uploadImage: {
          server: window.VITE_API_BASE_PATH + '/config/manage/uploadImg',
          fieldName: 'file',
          maxFileSize: 2 * 1024 * 1024, // 2MB
          maxNumberOfFiles: 5,
          allowedFileTypes: ['image/*'],
          metaWithUrl: true,
          withCredentials: false,
          headers: {
            Authorization: `Bearer ${token}`
          },
          onBeforeUpload(file: File) {
            // TS 语法
            // onBeforeUpload(file) {    // JS 语法
            // file 选中的文件，格式如 { key: file }
            console.log('knaknak===', file)
            return file

            // 可以 return
            // 1. return file 或者 new 一个 file ，接下来将上传
            // 2. return false ，不上传这个 file
          },
          // 自定义插入图片
          customInsert(res: any, insertFn: InsertFnType) {
            // TS 语法
            // customInsert(res, insertFn) {                  // JS 语法
            // res 即服务端的返回结果
            console.log('kankankan0000', res)
            let url = window.VITE_API_BASE_PATH + res.data
            let alt = '图片'
            let href = '图片'
            // 从 res 中找到 url alt href ，然后插入图片
            insertFn(url, alt, href)
          },

          // 上传进度的回调函数
          onProgress(progress: number) {
            // TS 语法
            // onProgress(progress) {       // JS 语法
            // progress 是 0-100 的数字
            console.log('progress', progress)
          },

          // 单个文件上传成功之后
          onSuccess(file: File, res: any) {
            // TS 语法
            // onSuccess(file, res) {          // JS 语法
            console.log(`${file.name} 上传成功`, res)
          },

          // 单个文件上传失败
          onFailed(file: File, res: any) {
            // TS 语法
            // onFailed(file, res) {           // JS 语法
            console.log(`${file.name} 上传失败`, res)
          },

          // 上传错误，或者触发 timeout 超时
          onError(file: File, err: any, res: any) {
            // TS 语法
            // onError(file, err, res) {               // JS 语法
            console.log(`${file.name} 上传出错`, err, res)
          }
        },
        uploadVideo: {
          server: window.VITE_API_BASE_PATH + '/geom/v1/uploadVideo',
          fieldName: 'file',
          maxFileSize: 50 * 1024 * 1024, // 50MB
          maxNumberOfFiles: 1,
          allowedFileTypes: ['video/*'],
          withCredentials: false,
          headers: {
            Authorization: `Bearer ${token}`
          },
          onBeforeUpload(file: File) {
            ElMessage({
              message: '视频正在上传中,请耐心等待',
              duration: 0,
              customClass: 'uploadTip',
              showClose: true
            })
            return file
          },

          // 自定义插入视频
          customInsert(res, insertFn) {
            // 因为自定义插入导致onSuccess与onFailed回调函数不起作用,自己手动处理
            // 先关闭等待的Message
            ElMessage.closeAll()
            if (res.code === 1) {
              ElMessage.success({
                message: `上传成功`
              })
            } else {
              ElMessage.error({
                message: `上传失败，请重新尝试`
              })
            }
            insertFn(window.VITE_API_BASE_PATH + res.data, window.VITE_API_BASE_PATH + res.data)
          },
          onSuccess(file: File, res: any) {
            console.log(`${file.name} uploaded successfully`, res)
          },
          onFailed(file: File, res: any) {
            console.log(`${file.name} upload failed`, res)
          },
          onError(file: File, err: any, res: any) {
            console.log(`${file.name} upload error`, err, res)
          }
        }
      }
    },
    props.editorConfig || {}
  )
})

const editorStyle = computed(() => {
  return {
    height: isNumber(props.height) ? `${props.height}px` : props.height
  }
})

// 回调函数
const handleChange = (editor: IDomEditor) => {
  emit('change', editor)
}

// 组件销毁时，及时销毁编辑器
onBeforeUnmount(() => {
  const editor = unref(editorRef.value)

  // 销毁，并移除 editor
  editor?.destroy()
})

const getEditorRef = async (): Promise<IDomEditor> => {
  await nextTick()
  return unref(editorRef.value) as IDomEditor
}

defineExpose({
  getEditorRef
})
</script>

<template>
  <div class="border-1 border-solid border-[var(--el-border-color)] z-10">
    <!-- 工具栏 -->
    <Toolbar
      :editor="editorRef"
      :editorId="editorId"
      class="border-0 b-b-1 border-solid border-[var(--el-border-color)]"
    />
    <!-- 编辑器 -->
    <Editor
      v-model="valueHtml"
      :editorId="editorId"
      :defaultConfig="editorConfig"
      :style="editorStyle"
      @on-change="handleChange"
      @on-created="handleCreated"
    />
  </div>
</template>

<style src="@wangeditor/editor/dist/css/style.css"></style>
